package com.acme.bankapp.service.bank;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

import com.acme.bankapp.domain.bank.AbstractAccount;
import com.acme.bankapp.domain.bank.Account;
import com.acme.bankapp.domain.bank.AccountExistsException;
import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.domain.bank.Client;
import com.acme.bankapp.domain.bank.ClientExistsException;

/**
 * Service that performs operations under a bank, such as adding clients, managing accounts etc.
 * @author Artem Nikitin
 *
 */
public class BankService implements IBankService {
	@Override
	public void addClient(Bank bank, Client client) throws ClientExistsException {
		if (client == null) {
			throw new IllegalArgumentException("Client cannot be null");
		}
		if (getClientByName(bank, client.getName()) != null) {
			throw new ClientExistsException("Client " + client.getName() + " already exists");
		}
		bank.addClient(client);
	}
	
	/**
	 * Adds account to client. 
	 * @param client - client
	 * @param account - account
	 * @throws AccountExistsException 
	 */
	@Override
	public void addAccount(Client client, AbstractAccount account) throws AccountExistsException {
		client.addAccount(account);
	}
	
	/**
	 * Returns client with specified name. If there is no clients with such name returns null
	 * @param name - name of client
	 * @return client with particular name or {@code null} if there is no clients with such name.
	 */
	@Override
	public Client getClientByName(Bank bank, String name) {
		for (Client client : bank.getClients()) {
			if (client.getName().equals(name)) {
				return client;
			}
		}
		return null;
	}
	
	public void printMaxAmountToWithdraw(Bank bank) {
		for (Client client : bank.getClients()) {
			System.out.print(client.getClientSalutation() + ": ");
			double maxAmountToWithdraw = 0;
			for(Account account : client.getAccounts()) {
				maxAmountToWithdraw += account.maxAmountToWithdraw();
			}
			System.out.println(maxAmountToWithdraw);
		}
	}
	
	/**
	 * Save bank data into file. For simplicity it doesn't handle exceptions
	 * @param bank
	 * @param os
	 */
	public void writeBank(Bank bank, OutputStream os) {
		try (ObjectOutputStream oos = new ObjectOutputStream(
				new BufferedOutputStream(os))){
			oos.writeObject(bank);	
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Load bank data from file. For simplicity it doesn't handle exceptions
	 * @param is
	 */
	public Bank readBank(InputStream is) {
		try (ObjectInputStream ois = new ObjectInputStream(
				new BufferedInputStream(is))){
			return (Bank) ois.readObject();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
	
}
